﻿/*
 *  XTL - XNA Tool Library, a collection with usefull XNA classes
 * 
 *  Copyright (C) 2009 Daniel Schiffner, Sebastian Schäfer
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 *  
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License 
 *  along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace XTL.Models
{
    /// <summary>
    /// Class for universal models.
    /// </summary>
    /// <typeparam name="T">VertexDataType of the model</typeparam>
    public class BasicModel<T> : DrawableModel where T : struct
    {
        /// <summary>
        /// Gets/Sets the vertices
        /// </summary>
        public T[] Vertices { get; set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="g">Reference to the GraphicsDeviceManager</param>
        public BasicModel(ref GraphicsDeviceManager g)
            : base (ref g)
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="g">Reference to the GraphicsDeviceManager</param>
        /// <param name="vd">The vertex declaration</param>
        public BasicModel(ref GraphicsDeviceManager g, VertexDeclaration vd)
            : base(ref g)
        {
            VertexDeclaration = vd;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="g">Reference to the GraphicsDeviceManager</param>
        /// <param name="vertices">Array of vertex data</param>
        /// <param name="indices">Array of indices</param>
        /// <param name="primitiveCount">Number of primitives to render</param>
        public BasicModel(ref GraphicsDeviceManager g, T[] vertices, short[] indices, int primitiveCount)
            : base(ref g)
        {
            SetData(vertices, indices, primitiveCount);
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="g">Reference to the GraphicsDeviceManager</param>
        /// <param name="vd">The vertex declaration</param>
        /// <param name="vertices">Array of vertex data</param>
        /// <param name="indices">Array of indices</param>
        /// <param name="primitiveCount">Number of primitves to render</param>
        public BasicModel(ref GraphicsDeviceManager g, VertexDeclaration vd, T[] vertices, short[] indices, int primitiveCount)
            :base(ref g)
        {
            SetData(vertices, indices, primitiveCount);
            VertexDeclaration = vd;
        }

        /// <summary>
        /// Sets the data needed for rendering.
        /// </summary>
        /// <param name="vertices">Array of vertices</param>
        /// <param name="indices">Array of indices</param>
        /// <param name="primitiveCount">Number of primitives to render</param>
        public void SetData(T[] vertices, short[] indices, int primitiveCount)
        {
            Vertices = vertices;
            Indices = indices;
            PrimitiveCount = primitiveCount;
        }

        /// <summary>
        /// Creates a copy of the model.
        /// </summary>
        /// <returns>Returns a copy of the current model</returns>
        public BasicModel<T> Clone()
        {
            return new BasicModel<T>(ref this.graphics, VertexDeclaration, Vertices, Indices, PrimitiveCount);
        }

        /// <summary>
        /// Draws the model.
        /// </summary>
        public override void Draw()
        {
            Graphics.GraphicsDevice.VertexDeclaration = VertexDeclaration;
            Graphics.GraphicsDevice.RenderState.CullMode = CullMode;

            Graphics.GraphicsDevice.DrawUserIndexedPrimitives<T>(
                RenderType,     //Rendertype
                Vertices,                     //Vertices
                0,                              //start offset
                Vertices.Length,              //num vertices
                Indices,              //Indices
                0,                              //start offset
                PrimitiveCount    //num primitives
            );
        }

        /// <summary>
        /// Draws the model using effect's CurrentTechnique
        /// <param name="effect">the effect used to draw the model</param>
        /// </summary>
        public void Draw(Effect effect)
        {
            effect.Begin();

            foreach (EffectPass pass in effect.CurrentTechnique.Passes)
            {
                pass.Begin();

                Draw();

                pass.End();
            }
            effect.End();
        }

    }
}
